﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace Quizz.DataRepository.AdoNet
{
    public class SafeDataReader : IDataReader
    {
        #region Fields

        private readonly IDataReader _dataReader;

        #endregion

        #region Constructor

        public SafeDataReader(IDataReader reader)
        {
            _dataReader = reader;
        }

        #endregion

        #region Reader methods

        public void Dispose()
        {
            _dataReader.Close();
            _dataReader.Dispose();
        }

        public string GetName(int i)
        {
            return _dataReader.GetName(i);
        }

        public string GetDataTypeName(int i)
        {
            return _dataReader.GetDataTypeName(i);
        }

        public string GetDataTypeName(string name)
        {
            return GetDataTypeName(GetOrdinal(name));
        }

        public Type GetFieldType(int i)
        {
            return _dataReader.GetFieldType(i);
        }

        public Type GetFieldType(string name)
        {
            return GetFieldType(GetOrdinal(name));
        }

        public object GetValue(int i)
        {
            return _dataReader.IsDBNull(i) ? null : _dataReader.GetValue(i);
        }

        public object GetValue(string name)
        {
            return GetValue(GetOrdinal(name));
        }

        public int GetValues(object[] values)
        {
            return _dataReader.GetValues(values);
        }

        public int GetOrdinal(string name)
        {
            return _dataReader.GetOrdinal(name);
        }

        public bool GetBoolean(int i)
        {
            return !(_dataReader[i] is DBNull) && _dataReader.GetBoolean(i);
        }

        public bool GetBoolean(string name)
        {
            return GetBoolean(GetOrdinal(name));
        }

        public bool? GetNullableBoolean(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetBoolean(i);
        }

        public bool? GetNullableBoolean(string name)
        {
            return GetNullableBoolean(GetOrdinal(name));
        }

        public byte GetByte(int i)
        {
            return _dataReader.IsDBNull(i) ? (byte) 0 : _dataReader.GetByte(i);
        }
        
        public byte GetByte(string name)
        {
            return GetByte(GetOrdinal(name));
        }

        public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
        {
            if (_dataReader.IsDBNull(i))
                return 0;
            return _dataReader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
        }

        public long GetBytes(string name, long fieldOffset, byte[] buffer, int bufferoffset, int length)
        {
            return GetBytes(GetOrdinal(name), fieldOffset, buffer, bufferoffset, length);
        }

        public char GetChar(int i)
        {
            if (_dataReader.IsDBNull(i))
                return char.MinValue;
            var myChar = new char[1];
            _dataReader.GetChars(i, 0, myChar, 0, 1);
            return myChar[0];
        }

        public char GetChar(string name)
        {
            return GetChar(GetOrdinal(name));
        }

        public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
        {
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetChars(i, fieldoffset, buffer, bufferoffset, length);
        }

        public long GetChars(string name, long fieldoffset, char[] buffer, int bufferoffset, int length)
        {
            return GetChars(GetOrdinal(name), fieldoffset, buffer, bufferoffset, length);
        }

        public Guid GetGuid(int i)
        {
            return _dataReader.IsDBNull(i) ? Guid.Empty : _dataReader.GetGuid(i);
        }

        public Guid GetGuid(string name)
        {
            return GetGuid(GetOrdinal(name));
        }

        public Guid? GetNullableGuid(int i)
        {
            return _dataReader.IsDBNull(i) ? (Guid?) null : _dataReader.GetGuid(i);
        }

        public Guid? GetNullableGuid(string name)
        {
            return GetNullableGuid(GetOrdinal(name));
        }
    
        public short GetInt16(int i)
        {
            return _dataReader.IsDBNull(i) ? (short)0 : _dataReader.GetInt16(i);
        }

        public short GetInt16(string name)
        {
            return GetInt16(GetOrdinal(name));
        }

        public short? GetNullableInt16(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetInt16(i);
        }

        public short? GetNullableInt16(string name)
        {
            return GetNullableInt16(GetOrdinal(name));
        }

        public int GetInt32(int i)
        {
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetInt32(i);
        }

        public int GetInt32(string name)
        {
            return GetInt32(GetOrdinal(name));
        }

        public int? GetNullableInt32(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetInt32(i);
        }

        public int? GetNullableInt32(string name)
        {
            return GetNullableInt32(GetOrdinal(name));
        }

        public long GetInt64(int i)
        {
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetInt64(i);
        }

        public long GetInt64(string name)
        {
            return GetInt64(GetOrdinal(name));
        }

        public long? GetNullableInt64(int i)
        {
            return _dataReader.IsDBNull(i) ? (long?) null : _dataReader.GetInt64(i);
        }

        public long? GetNullableInt64(string name)
        {
            return GetNullableInt64(GetOrdinal(name));
        }

        public float GetFloat(int i)
        {
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetFloat(i);
        }
        public float GetFloat(string name)
        {
            return GetFloat(GetOrdinal(name));
        }

        public float? GetNullableFloat(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetFloat(i);
        }

        public float? GetNullableFloat(string name)
        {
            return GetNullableFloat(GetOrdinal(name));
        }

        public double GetDouble(int i)
        {
            if (_dataReader.IsDBNull(i))
                return 0;
            return _dataReader.GetDouble(i);
        }

        public double GetDouble(string name)
        {
            return GetDouble(GetOrdinal(name));
        }

        public double? GetNullableDouble(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetDouble(i);
        }

        public double? GetNullableDouble(string name)
        {
            return GetNullableDouble(GetOrdinal(name));
        }

        public string GetString(int i)
        {
            return _dataReader.IsDBNull(i) ? string.Empty : _dataReader.GetString(i);
        }

        public string GetString(string name)
        {
            return GetString(GetOrdinal(name));
        }

        public decimal GetDecimal(int i)
        {
            return _dataReader.IsDBNull(i) ? 0 : _dataReader.GetDecimal(i);
        }

        public decimal GetDecimal(string name)
        {
            return GetDecimal(GetOrdinal(name));
        }

        public decimal? GetNullableDecimal(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetDecimal(i);
        }

        public decimal? GetNullableDecimal(string name)
        {
            return GetNullableDecimal(GetOrdinal(name));
        }

        public DateTime GetDateTime(int i)
        {
            return _dataReader.IsDBNull(i) ? DateTime.MinValue : _dataReader.GetDateTime(i);
        }

        public DateTime GetDateTime(string name)
        {
            return GetDateTime(GetOrdinal(name));
        }

        public DateTime? GetNullableDateTime(int i)
        {
            if (_dataReader.IsDBNull(i))
                return null;
            return _dataReader.GetDateTime(i);
        }

        public DateTime? GetNullableDateTime(string name)
        {
            return GetNullableDateTime(GetOrdinal(name));
        }

        public IDataReader GetData(int i)
        {
            return _dataReader.GetData(i);
        }

        public IDataReader GetData(string name)
        {
            return GetData(GetOrdinal(name));
        }

        public bool IsDBNull(int i)
        {
            return _dataReader.IsDBNull(i);
        }

        public int FieldCount
        {
            get { return _dataReader.FieldCount; }
        }

        object IDataRecord.this[int i]
        {
            get { return _dataReader.IsDBNull(i) ? null : _dataReader[i]; }
        }

        public object this[string name]
        {
            get
            {
                var val = _dataReader[name];
                return DBNull.Value.Equals(val) ? null : _dataReader[name];
            }
        }

        public void Close()
        {
            _dataReader.Close();
        }

        public DataTable GetSchemaTable()
        {
            return _dataReader.GetSchemaTable();
        }

        public bool NextResult()
        {
            return _dataReader.NextResult();
        }

        public bool Read()
        {
            return _dataReader.Read();
        }

        public int Depth
        {
            get { return _dataReader.Depth; }
        }

        public bool IsClosed
        {
            get { return _dataReader.IsClosed; }
        }

        public int RecordsAffected
        {
            get { return _dataReader.RecordsAffected; }
        }

        #endregion

        #region Public methods

        public XmlDocument GetXml(int i)
        {
            var doc = new XmlDocument();
            if (_dataReader.IsDBNull(i))
                return doc;
            doc.Load(_dataReader.GetString(i));
            return doc;
        }

        public XmlDocument GetXml(string name)
        {
            return GetXml(GetOrdinal(name));
        }

        #endregion

        #region Private methods
        #endregion
    }
}
